package zwz.importTask.strategy;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.util.ConverterUtils;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import zwz.importTask.enums.ExcelImportExportSateEnum;
import zwz.importTask.enums.ImportAndExportTaskEnum;
import zwz.importTask.mapper.BiDataImportTaskMapper;
import zwz.importTask.pojo.BiDataImportTaskPO;
import zwz.importTask.utils.ExportCellWriteHandler;
import zwz.importTask.utils.ImportContext;
import zwz.importTask.utils.ImportThreadLocalUtils;
import zwz.importTask.utils.ImportUtils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.*;

@Slf4j
public abstract class AbstractExcelImportStrategy<T> {
    @Autowired
    private BiDataImportTaskMapper biDataImportTaskMapper;





    // 模板方法，定义导入逻辑
    final public void doImport(byte[] fileData, Integer fileType, String fileName) {
        ByteArrayInputStream inputStream = new ByteArrayInputStream(fileData);
//        ByteArrayInputStream uploadStream = new ByteArrayInputStream(fileData);
        ImportContext<T> importContext = ImportThreadLocalUtils.getContext();
        importContext.setFileType(fileType);
        importContext.setFileName(fileName);
        //初始文件上传OSS
//        String originFileUrl = AliYunOssFileUtils.uploadFile("importDetails/", UUID.randomUUID() + ".xlsx", uploadStream);
//        ImportThreadLocalUtils.getContext().setOriginFileUrl(originFileUrl);
        // 读取时分批处理
        readData(inputStream);

    }

    // 定义读取Excel数据的方法，处理分批逻辑
    public final void readData(InputStream inputStream) {
        EasyExcel.read(inputStream, getTypeClass(), new AnalysisEventListener<T>() {
            private List<String> headList;

            @Override
            public void invoke(T data, AnalysisContext context) {
                // 过滤空行
                if (data == null || ImportUtils.allFieldsAreEmpty(data)) {
                    return;
                }
                ImportContext<T> importContext = ImportThreadLocalUtils.getContext();
                //获取粗略的总行数，用于初始化导入任务记录
                if (importContext.getTotalRecords() == null || importContext.getTotalRecords() == 0) {
                    importContext.setTotalRecords(context.readSheetHolder().getApproximateTotalRowNumber() - 1);
                    initImportRecord();
                }
                // 实际总行数、一条一条累加
                importContext.getTotalCount().incrementAndGet();

                if (validateData(data)) {
                    importContext.getSuccessList().add(data);
                    importContext.getTotalSuccessCount().incrementAndGet();
                } else {
                    importContext.getFailureList().add(data);
                    importContext.getTotalFailureList().add(data);
                    importContext.getTotalFailureCount().incrementAndGet();
                }
                importContext.getBatchList().add(data);

                // 每批次数据处理
                if (importContext.getBatchList().size() >= getBatchSize()) {
                    //批处理逻辑
                    batchHandleImportData(importContext);
                    importContext.getBatchList().clear();
                    importContext.getSuccessList().clear();
                    importContext.getFailureList().clear();

                }
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                ImportContext<T> importContext = ImportThreadLocalUtils.getContext();
                // 处理剩余数据
                if (!importContext.getBatchList().isEmpty()) {
                    batchHandleImportData(importContext);
                }

                //生成错误数据 上传到OSS
                if (!importContext.getFailureList().isEmpty()) {
                    ByteArrayOutputStream os = new ByteArrayOutputStream();
                    // 将校验错误的数据写入OSS
                    ExcelWriterBuilder excelWriterBuilder = EasyExcel.write(os, getTypeClass()).registerWriteHandler(new ExportCellWriteHandler(this.headList.size()));

                    excelWriterBuilder.autoCloseStream(true).sheet("导入失败数据").doWrite(importContext.getTotalFailureList());
                    byte[] content = os.toByteArray();
                    InputStream is = new ByteArrayInputStream(content);
//                    失败的文件写入OSS
//                    String errorFileUrl = AliYunOssFileUtils.uploadFile("importDetails/errorDetails", UUID.randomUUID() + ".xlsx", is);
//                    importContext.setErrorFileUrl(errorFileUrl);
                }

                //最后处理逻辑
                finallyUpdateImportRecord(importContext.getBiDataImportTaskPO());

            }

            @Override
            public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
                Map<Integer, String> integerStringMap = ConverterUtils.convertToStringMap(headMap, context);
                List<String> headList = new ArrayList<>(integerStringMap.values());
                this.headList = headList;
            }
        }).sheet().doRead();
    }

    /**
     * 批量处理导入数据
     */
    final public void batchHandleImportData(ImportContext<T> importContext) {
        // 保存成功的数据
        handleSuccessData(importContext.getSuccessList());

        // 处理批次失败数据（选择实现）
        handleFailureData(importContext.getFailureList());

        //更新导入状态
        updateImportRecord(importContext.getBiDataImportTaskPO());

    }


    /**
     * 初始化导入信息
     */
    private void initImportRecord() {
        ImportContext<Object> importContext = ImportThreadLocalUtils.getContext();
        BiDataImportTaskPO biDataImportTaskPO = new BiDataImportTaskPO();
        biDataImportTaskPO.setTaskNo(UUID.randomUUID().toString());
        biDataImportTaskPO.setImportDataType(importContext.getFileType());
        biDataImportTaskPO.setMenuName(ImportAndExportTaskEnum.getMenuNameByType(importContext.getFileType()));
        biDataImportTaskPO.setStatus(ExcelImportExportSateEnum.SUCCESS.getKey());
        biDataImportTaskPO.setOriginImportFileUrl(importContext.getOriginFileUrl());
        biDataImportTaskPO.setErrorFileUrl("");
        biDataImportTaskPO.setCreatedTime(new Date());
        biDataImportTaskPO.setStartTime(new Date());
        biDataImportTaskPO.setModifiedTime(new Date());
        biDataImportTaskPO.setFileName(importContext.getFileName());
        biDataImportTaskPO.setTotalRecord(importContext.getTotalRecords());
        biDataImportTaskPO.setSucceedRecord(importContext.getTotalSuccessCount().get());
        biDataImportTaskPO.setFailRecord(importContext.getTotalFailureCount().get());
        biDataImportTaskMapper.insert(biDataImportTaskPO);
        ImportThreadLocalUtils.getContext().setBiDataImportTaskPO(biDataImportTaskPO);
    }

    /**
     * 更新导入记录
     *
     * @param biDataImportTaskPO
     */
    private void updateImportRecord(BiDataImportTaskPO biDataImportTaskPO) {
        ImportContext<T> importContext = ImportThreadLocalUtils.getContext();
        biDataImportTaskPO.setFailRecord(importContext.getTotalFailureCount().get());
        biDataImportTaskPO.setSucceedRecord(importContext.getTotalSuccessCount().get());
        biDataImportTaskPO.setModifiedTime(new Date());

        biDataImportTaskMapper.updateById(biDataImportTaskPO);
        importContext.setBiDataImportTaskPO(biDataImportTaskPO);
    }


    //最终处理状态
    private void finallyUpdateImportRecord(BiDataImportTaskPO biDataImportTask) {
        ImportContext<T> importContext = ImportThreadLocalUtils.getContext();
        if (importContext.getTotalSuccessCount().get() == importContext.getTotalCount().get()) {
            biDataImportTask.setStatus(ExcelImportExportSateEnum.SUCCESS.getKey());
        } else if (importContext.getTotalCount().get() == importContext.getTotalFailureCount().get()) {
            biDataImportTask.setStatus(ExcelImportExportSateEnum.ALL_FAIL.getKey());
        } else {
            biDataImportTask.setStatus(ExcelImportExportSateEnum.PART_SUCCESS.getKey());
        }

        biDataImportTask.setErrorFileUrl(importContext.getErrorFileUrl());
        biDataImportTask.setSucceedRecord(importContext.getTotalSuccessCount().get());
        biDataImportTask.setTotalRecord(importContext.getTotalCount().get());
        biDataImportTask.setFailRecord(importContext.getTotalFailureCount().get());
        biDataImportTask.setModifiedTime(new Date());
        biDataImportTask.setEndTime(new Date());
        biDataImportTask.setTime((int) (System.currentTimeMillis() - (biDataImportTask.getStartTime().getTime()))/ 1000 );
        biDataImportTaskMapper.updateById(biDataImportTask);
        importContext.setBiDataImportTaskPO(biDataImportTask);
    }

    protected abstract void handleFailureData(List<T> failureList);

    // 获取数据类型类对象，子类实现
    public abstract Class<T> getTypeClass();


    // 校验数据，子类实现
    public abstract boolean validateData(T data);

    // 保存数据，子类实现
    public abstract void handleSuccessData(List<T> dataList);

    // 默认5000、不同业务场景实现覆盖
    public abstract int getBatchSize();
}
